module IPFS.Client.Command.Stats (
 bitswap,
 repo,
 bw,
 bwPoll,
 BWInfo(..)
) where

import Prelude

import Data.Argonaut (class DecodeJson, Json, decodeJson)
import Data.Argonaut.Decode ((.:))
import Data.BigInt (BigInt)
import Data.Either (Either)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep.Show (genericShow)
import Data.Integral (toBigInt)
import Data.Maybe (Maybe(..))
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect.Aff (Aff)
import Foreign.Object as O
import IPFS.Client (Client)
import IPFS.Client.Command (Command, defCommand, genQSObject)
import IPFS.Client.Command.Common (RepoStat, Stat)
import IPFS.Client.Utils.SendRequest (execEffectStreamDecodeJsonCommand, execJsonCommand)
import Network.HTTP as HTTP
------------------------bitswap---------------------------------
bitswapCommand::Command
bitswapCommand = defCommand { path = "stats/bitswap", args = Nothing, qs = O.empty }

bitswap::Client -> Aff (Either String Stat)
bitswap client = execJsonCommand client bitswapCommand

------------------------repo-------------------------------------
repoCommand::Command
repoCommand = defCommand { path = "stats/repo",args = Nothing, qs = O.empty}

repo::Client -> Aff (Either String RepoStat)
repo client = execJsonCommand client repoCommand

------------------------bw-------------------------------------
newtype BWInfo = BWInfo {
    totalIn ::BigInt,
    totalOut::BigInt,
    rateIn::Number,
    rateOut::Number
}

derive instance genericBWInfo :: Generic BWInfo _
instance showBWInfo :: Show BWInfo where
  show s = genericShow s

instance bWInfoDecodeJson :: DecodeJson BWInfo where
  decodeJson::Json -> Either String BWInfo
  decodeJson json = do
    dJson <- decodeJson json
    totalIn::Number <- dJson .: "TotalIn"
    totalOut::Number <- dJson .: "TotalOut"
    rateIn <- dJson .: "RateIn"
    rateOut <- dJson .: "RateOut"
    pure $ BWInfo {totalIn:toBigInt totalIn,
                   totalOut:toBigInt totalIn,
                   rateIn:rateIn,
                   rateOut:rateOut
                   }

bwCommand::Boolean -> Maybe String -> Maybe String -> Maybe Boolean -> Maybe String ->  Command
bwCommand disableChunkJson peer proto poll interval = defCommand  { path = "stats/bw",
                                                   args = Nothing, 
                                                   qs = genQSObject ["peer"     /\ peer,
                                                                     "proto"    /\ proto,
                                                                     "poll"     /\  (show <$> poll),
                                                                     "interval" /\ interval
                                                                    ] O.empty,
                                                   disableChunkJson = disableChunkJson
                                                 }

bw::Client -> Maybe String -> Maybe String  -> Maybe String -> Aff (Either String BWInfo)
bw client peer proto interval = execJsonCommand client $ bwCommand true peer proto Nothing interval


bwPoll::Client -> (HTTP.Response -> Effect Unit) -> (Either String BWInfo -> Effect Unit) -> Maybe String -> Maybe String  -> Maybe String -> Effect Unit
bwPoll client startCallback callback peer proto interval = do 
  let cmd = bwCommand false peer proto (Just true) interval
  _ <- execEffectStreamDecodeJsonCommand  client cmd startCallback callback
  pure unit
